package com.pxst.fi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pxst.bank.entity.SysAvailableBankEntity;
import com.pxst.bank.entity.SysBankCardEntity;
import com.pxst.bank.entity.SysBankCardGroupEntity;
import com.pxst.bank.mapper.SysAvailableBankMapper;
import com.pxst.bank.mapper.SysBankCardMapper;
import com.pxst.bank.service.SysAvailableBankService;
import com.pxst.bank.service.SysBankCardGroupService;
import com.pxst.bank.service.SysBankCardService;
import com.pxst.enums.AmqEnum;
import com.pxst.enums.RedisKeyEnums;
import com.pxst.enums.TxnModeEnums;
import com.pxst.exception.BusinessException;
import com.pxst.fi.entity.*;
import com.pxst.fi.mapper.SysFiOrderMapper;
import com.pxst.fi.req.FiCreateOrderReq;
import com.pxst.fi.req.FiOrderReq;
import com.pxst.fi.resp.FiOrderResp;
import com.pxst.fi.service.*;
import com.pxst.merchant.entity.SysMerchantInfo;
import com.pxst.merchant.service.SysMerchantInfoService;
import com.pxst.resp.ApiResp;
import com.pxst.resp.PageResp;
import com.pxst.sys.entity.SysConfigDetail;
import com.pxst.sys.entity.SysCurrencyConfigEntity;
import com.pxst.sys.req.ConfigRedisRsp;
import com.pxst.sys.req.ConfigRedisRspSub;
import com.pxst.utils.AltIdUtils;
import com.pxst.utils.AmqUtils;
import com.pxst.utils.RedisUtils;
import icu.mhb.mybatisplus.plugln.base.service.impl.JoinServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.pxst.fi.constants.FiConstant.*;
import static com.pxst.fi.constants.NoticeConstant.*;

/**
 * @author yangxy
 * @version 创建时间：2023年9月7日 下午2:47:50
 */
@Slf4j
@Service
public class FiServiceImpl extends JoinServiceImpl<SysFiOrderMapper, SysFiOrderEntity> implements FiService {
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private SysMerchantInfoService sysMerchantInfoService;
    @Autowired
    private SysBankCardGroupService sysBankCardGroupService;
    @Autowired
    private SysAvailableBankService sysAvailableBankService;
    @Autowired
    private SysAvailableBankMapper sysAvailableBankMapper;
    @Autowired
    private SysBankCardMapper sysBankCardMapper;
    @Autowired
    private AmqUtils amqUtils;
    @Autowired
    private SysFiOrderMapper fiOrderMapper;
    @Autowired
    private SysThirdPartySettingService thirdPartySettingService;
    @Autowired
    private SysThirdPartyConfigService thirdPartyConfigService;
    @Autowired
    private SysBankBillService bankBillService;
    @Autowired
    private SysBankCardService bankCardService;
	@Autowired
	private SysLogLastPageService logLastPageService;

    @Override
    @SuppressWarnings("unchecked")
    public ApiResp<String> createOrder(FiCreateOrderReq fiCreateOrderReq) {
        // TODO Auto-generated method stub
        if (fiCreateOrderReq.getOrder_type().equals("100") && StringUtils.isEmpty(fiCreateOrderReq.getFrom_bank())) {
            return ApiResp.paramError("银行代码不能为空");
        }
        SysMerchantInfo sysMerchantInfoEntity = sysMerchantInfoService.getById(fiCreateOrderReq.getMerchantId());
        if (ObjectUtils.isEmpty(sysMerchantInfoEntity)) {
            throw new BusinessException("商户不存在");
        }

        switch (fiCreateOrderReq.getOrder_type()) {
            case "QRPay":
                createOrderByQRPay(sysMerchantInfoEntity, fiCreateOrderReq);
                break;
            default:
                throw new BusinessException("订单充值类型不存在");
        }
        return null;
    }

    @Override
    public ApiResp<PageResp<FiOrderResp>> getAllByCondition(FiOrderReq fiOrderReq) {
        Page<FiOrderResp> page = null;
        List<FiOrderResp> fiOrderResps = null;
        // 数据处理
        FiOrderReq paramsHandle = paramsHandle(fiOrderReq);
        // 查询分页数据
        PageHelper.startPage(fiOrderReq.getPage(), fiOrderReq.getRp());
        page = (Page<FiOrderResp>) fiOrderMapper.getAllByCondition(paramsHandle);

        // 查询结果处理
        fiOrderResps = respHandle(page.getResult());
        // 获取小计数据
        Map<String, BigDecimal> subTotals = getSubTotals(fiOrderResps);

        Map<String, BigDecimal> totals = subTotals;
        if (page.getTotal() > 0 && page.getTotal() > 100) {
            // 获取总计数据
            totals = fiOrderMapper.getTotals(fiOrderReq);
        }

        return ApiResp.page(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), fiOrderResps, subTotals, totals);
    }

    @Override
    public List<FiExcelModel> download(FiOrderReq fiOrderReq) {
        // 数据处理
        FiOrderReq paramsHandle = paramsHandle(fiOrderReq);
        // 查询数据
        List<FiOrderResp> allOrder = fiOrderMapper.getAllByCondition(paramsHandle);
        // 查询结果处理
        allOrder = respHandle(allOrder);
        // 为模型类添加数据
        List<FiExcelModel> fiExcelModels = addDataForExcel(allOrder);
        return fiExcelModels;
    }

    /**
     * 计算小计数据
     *
     * @param FiOrderRespList
     * @return
     */
    private Map<String, BigDecimal> getSubTotals(List<FiOrderResp> FiOrderRespList) {

        BigDecimal orderAmount = new BigDecimal(0);
        BigDecimal requestAmount = new BigDecimal(0);
        BigDecimal paidAmount = new BigDecimal(0);
        BigDecimal lossAmount = new BigDecimal(0);
        BigDecimal rate = new BigDecimal(0);

        for (FiOrderResp fiOrderResp : FiOrderRespList) {
            orderAmount = orderAmount.add(fiOrderResp.getOrderAmount());
            requestAmount = requestAmount.add(fiOrderResp.getRequestAmount());
            paidAmount = paidAmount.add(fiOrderResp.getPaidAmount());
            lossAmount = lossAmount.add(fiOrderResp.getLossAmount());
            if (fiOrderResp.getStatus() == STATUS_COMPLETED) {
                rate = rate.add(fiOrderResp.getRate());
            }
        }
        Map<String, BigDecimal> subTotal = new HashMap<>();
        subTotal.put("orderAmount", orderAmount);
        subTotal.put("requestAmount", requestAmount);
        subTotal.put("paidAmount", paidAmount);
        subTotal.put("lossAmount", lossAmount);
        subTotal.put("rate", rate);

        return subTotal;
    }

    /**
     * 添加excel表格数据
     *
     * @param allOrder
     * @return
     */
    private List<FiExcelModel> addDataForExcel(List<FiOrderResp> allOrder) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return allOrder.stream().map(order -> {
            FiExcelModel excelModel = new FiExcelModel();
            BeanUtils.copyProperties(order, excelModel);
            excelModel.setTo(getTo(order));
            if (StringUtils.isEmpty(excelModel.getAccountCode())) {
                // 查询银行卡信息
                SysBankCardEntity bankCard = bankCardService.getById(order.getCardId());
                if (ObjectUtils.isEmpty(bankCard)) {
                    throw new BusinessException("充值订单数据异常，充值银行卡不存在");
                }
                excelModel.setAccountCode(bankCard.getAccountCode());
            }
            excelModel.setCollectType(StringConcatNotNull(processTxnMode(order), "\n", order.getVndOtp()));
            excelModel.setInfo(StringConcatNotNull("MOID/商户订单号：", order.getReference(), "\nNote/备注：", order.getNote()));
            excelModel.setStatus(StringConcatNotNull(processStatus(order), "\n"
                    , processPairingBy(order), "\n"
                    , (!ObjectUtils.isEmpty(order.getCompletedAt()) ? format.format(order.getCompletedAt()) : "")
                    , "\n", processStatusDescription(order)));
            excelModel.setCreated(format.format(order.getCreatedAt()));
            excelModel.setVbs((!ObjectUtils.isEmpty(order.getVbPairingTime()) ? StringConcatNotNull(format.format(order.getVbPairingTime()), "\n#", order.getVbId().toString()) : null));
            excelModel.setVbs((!ObjectUtils.isEmpty(order.getSmPairingTime()) ? StringConcatNotNull(format.format(order.getSmPairingTime()), "\n#", order.getSmId().toString()) : null));
            excelModel.setUpdated(format.format(order.getUpdatedAt()));
            excelModel.setNtStatus(getNtStatus(order));
            excelModel.setMessage(getMessage(order));
            excelModel.setMode(order.getTxnMode() == 1 ? "IB" : "QR/TW");
            excelModel.setFiCreate(format.format(order.getCreatedAt()));
            excelModel.setFiComplete(format.format(order.getCompletedAt()));
            if (!ObjectUtils.isEmpty(order.getVbId())) {
                SysBankBillEntity bankBill = bankBillService.getById(order.getVbId());
                if (!ObjectUtils.isEmpty(bankBill)) {
                    excelModel.setUpdateMan(bankBill.getUpdater());
                    excelModel.setAutoManual(bankBill.getUpdater().equals("system") ? "自动对账" : "人工对账");
                    excelModel.setVbsCreate(format.format(bankBill.getCreatedAt()));
                    excelModel.setFiCreateAndVbsCreateComparison(
                            Math.abs((order.getCreatedAt().getTime() - bankBill.getCreatedAt().getTime()) / 1000)
                    );
                    excelModel.setFiCreateAndFiCompleteComparison(
                            Math.abs((order.getCreatedAt().getTime() - order.getCompletedAt().getTime()) / 1000)
                    );
                }
            }
            return excelModel;
        }).collect(Collectors.toList());
    }

    /**
     * 字符串拼接不拼接null的方法
     *
     * @return
     */
    private String StringConcatNotNull(String... args) {
        StringBuilder builder = new StringBuilder();
        for (String arg : args) {
            if (arg != null) {
                builder.append(arg);
            }
        }
        return builder.toString().trim();
    }

    /**
     * 获取汇出报表的message
     *
     * @param order
     * @return
     */
    private String getMessage(FiOrderResp order) {
        if (order.getMessage().startsWith("{")) {
            ObjectMapper objectMapper = new ObjectMapper();
            // 解析json字符串
            String createdAtString = null;
            try {
                JsonNode jsonNode = objectMapper.readTree(order.getMessage());
                createdAtString = jsonNode.get("created_at").asText();
                if (StringUtils.hasText(createdAtString)) {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date createdAt = format.parse(createdAtString);
                    String createdMan = jsonNode.get("created_man").asText();
                    String rawBody = jsonNode.get("rawBody").asText();
                    return StringConcatNotNull(format.format(createdAt), createdMan, "\n", rawBody);
                }
            } catch (JsonProcessingException e) {
                log.error("字符串message：" + order.getMessage() + "解析错误");
                e.printStackTrace();
            } catch (ParseException e) {
                log.error("Message中获取的createdAt格式转换错误：" + createdAtString);
                e.printStackTrace();
            }
        }
        return order.getMessage();
    }

    /**
     * 获取汇出报表的ntStatus字段
     *
     * @param order
     * @return
     */
    private String getNtStatus(FiOrderResp order) {
        if (ObjectUtils.isEmpty(order.getNoticeResult())) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String noticeResult = null;
        switch (order.getNoticeResult()) {
            case 0:
                noticeResult = RESULT_0;
            case 1:
                noticeResult = RESULT_1;
            case 2:
                noticeResult = RESULT_2;
            case 3:
                noticeResult = RESULT_3;
            case 4:
                noticeResult = RESULT_4;
            case 5:
                noticeResult = RESULT_5;
        }
        return StringConcatNotNull(noticeResult, "\n", order.getNoticeContent(), "\n", format.format(order.getNoticeUpdatedAt()));
    }

    /**
     * 处理汇出报表的StatusDescription
     *
     * @param order
     * @return
     */
    private String processStatusDescription(FiOrderResp order) {
        return order.getStatusDescription() == STATUS_DESCRIPTION_NO_CARD ? "No card available" : null;
    }

    /**
     * 处理汇出报表的pairingBy数据
     *
     * @param order
     * @return
     */
    private String processPairingBy(FiOrderResp order) {
        switch (order.getPairingBy()) {
            case 1:
                return "VBS";
            case 2:
                return "SMS";
            default:
                return null;
        }
    }

    /**
     * 处理汇出报表的status数据
     *
     * @return
     * @Author rj
     * @Date 2023年09月14日 14:06:06
     * @Param order
     */
    private String processStatus(FiOrderResp order) {
        Map<Integer, String> statusMap = new HashMap();
        statusMap.put(STATUS_PENDING, "Pending/等待中");
        statusMap.put(STATUS_PROCESSING, "Processing/处理中");
        statusMap.put(STATUS_COMPLETED, "Success/成功");
        statusMap.put(STATUS_MANUAL_PROCESS, "Manual process/手动流程");
        statusMap.put(STATUS_FAILED, "Failed/手动流程");
        return statusMap.get(order.getStatus());
    }

    /**
     * 处理汇出报表的txnMode数据
     *
     * @return
     * @Author rj
     * @Date 2023年09月14日 14:06:06
     * @Param order
     */
    private String processTxnMode(FiOrderResp order) {
        Map<Integer, String> txnModeMap = new HashMap();
        txnModeMap.put(TXN_MODE_BANK, "Bank");
        txnModeMap.put(TXN_MODE_QRPAY, "QR");
        txnModeMap.put(TXN_MODE_TRUE_WALLET, "TrueWallet");
        txnModeMap.put(TXN_MODE_VNPAY_ZALO_QR, "Zalo QR/Zalo 扫码");
        txnModeMap.put(TXN_MODE_VNPAY_MOMO_QR, "Momo QR/Momo 扫码");
        txnModeMap.put(TXN_MODE_VNPAY_VIETTEL_QR, "Viettelpay QR/Viettelpay 扫码");
        txnModeMap.put(TXN_MODE_VNPAY_BANK_QR, "Bank QR/银行卡扫码");
        txnModeMap.put(TXN_MODE_VNPAY_BANK, "Onling banking/网银");
        txnModeMap.put(TXN_MODE_VNPAY_BANK_CARD, "Bank transfer/银行卡转账");
        return txnModeMap.get(order.getTxnMode()) + (order.getTxnMode() == TXN_MODE_QRPAY
                && order.getCurrency().equals("THB")
                && StringUtils.hasText(order.getPromptpayCode()) ? "-" + order.getPromptpayCode().substring(order.getPromptpayCode().length() - 5) : "");
    }

    /**
     * 获取汇出报表的to值
     *
     * @return
     * @Author rj
     * @Date 2023年09月14日 11:45:33
     * @Param order
     */
    private String getTo(FiOrderResp order) {
        Map<Integer, String> toDesc = new HashMap();
        toDesc.put(TXN_MODE_VNPAY_ZALO_QR, "VNPAY_Zalo QR/VNPAY_Zalo 扫码");
        toDesc.put(TXN_MODE_VNPAY_MOMO_QR, "VNPAY_Momo QR/VNPAY_Momo 扫码");
        toDesc.put(TXN_MODE_VNPAY_VIETTEL_QR, "VNPAY_Viettelpay QR/VNPAY_Viettelpay 扫码");
        toDesc.put(TXN_MODE_VNPAY_BANK_QR, "VNPAY_");
        toDesc.put(TXN_MODE_VNPAY_BANK, "VNPAY_");
        return order.getIsTpi()
                ? (toDesc.get(order.getTxnMode()).equals("VNPAY_")
                ? toDesc.get(order.getTxnMode()) + order.getFromBank()
                : toDesc.get(order.getTxnMode()))
                : order.getToAccountCode();
    }

    /**
     * 处理查询传入参数
     *
     * @param fiOrderReq
     * @return
     */
    private FiOrderReq paramsHandle(FiOrderReq fiOrderReq) {
        FiOrderReq orderReq = new FiOrderReq();
        BeanUtils.copyProperties(fiOrderReq, orderReq);

        if (StringUtils.hasText(fiOrderReq.getFrom())) {
            orderReq.setFrom(fiOrderReq.getFrom().replaceAll("#^(?:\\w+/)?(?:\\w+\\-)?#", ""));
        }

        if (!ObjectUtils.isEmpty(fiOrderReq.getCompletedStartDate()) && fiOrderReq.getCurrency() != "CNY") {
            orderReq.setStatusList(Arrays.asList(3));
        }

        if (StringUtils.hasText(fiOrderReq.getAltId())) {
            Long fiId = AltIdUtils.restoreId(fiOrderReq.getAltId());
            orderReq.setFiId(fiId);
        }

        if (ObjectUtils.isEmpty(fiOrderReq.getTpiTxnMode()) && StringUtils.hasText(fiOrderReq.getDriver())) {
            // 查询第三方支付数据
            SysThirdPartyConfigEntity one = thirdPartyConfigService.getOne(
                    new LambdaQueryWrapper<SysThirdPartyConfigEntity>()
                            .eq(SysThirdPartyConfigEntity::getDriver, fiOrderReq.getDriver()));
            // 查询第三方支付设置(tpi110)数据
            List<SysThirdPartySettingEntity> list = thirdPartySettingService.list(
                    new LambdaQueryWrapper<SysThirdPartySettingEntity>()
                            .eq(SysThirdPartySettingEntity::getMerchantId, 0)
                            .eq(SysThirdPartySettingEntity::getThirdPartyConfigId, one.getId()));
            // 获取txnMode数据
            List<Integer> tpiTxnMode = list.stream().map(SysThirdPartySettingEntity::getTxnMode).collect(Collectors.toList());
            orderReq.setTpiTxnMode(tpiTxnMode);
        }

        // 交易模式有冲突，直接搜不到任何東西
        if (!(ObjectUtils.isEmpty(fiOrderReq.getTxnMode()) || ObjectUtils.isEmpty(fiOrderReq.getTpiTxnMode()))) {
            orderReq.setFiId(-1L);
        }
        return orderReq;
    }

    /**
     * 查询响应数据处理
     *
     * @return
     */
    private List<FiOrderResp> respHandle(List<FiOrderResp> FiOrderRespList) {
        return FiOrderRespList.stream().map(fiOrderResp -> {
            FiOrderResp resp = new FiOrderResp();
            BeanUtils.copyProperties(fiOrderResp, resp);
            // 添加订单号
            String altId = AltIdUtils.getAltId("D", fiOrderResp.getCreatedAt(), fiOrderResp.getFiId());
            resp.setAltId(altId);
            // 是否是第三方支付
            if (!ObjectUtils.isEmpty(fiOrderResp.getThirdId())) {
                resp.setIsTpi(fiOrderResp.getThirdId() > 0);
            } else {
                resp.setIsTpi(false);
            }
            // message处理
            resp.setMessage(getFiMessage(fiOrderResp));

            // isRunMon处理
            resp.setIsRunMon(getIsRunmon(fiOrderResp));

            // 是否有回调
            resp.setIsCallbackable(getIsCallbackable(fiOrderResp));

            // isErrurl处理
			SysLogLastPageEntity one = logLastPageService.getOne(new LambdaQueryWrapper<SysLogLastPageEntity>()
					.eq(StringUtils.hasText(fiOrderResp.getCommandId()), SysLogLastPageEntity::getCommandId, fiOrderResp.getCommandId()));
			resp.setIsErrurl(ObjectUtils.isEmpty(one) ? false : true);
			/*

			// 日期格式化
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			resp.setCreatedAt(dateFormat.format(fiOrderResp.getCreatedAt()));
			*/

            return resp;
        }).collect(Collectors.toList());
    }

    /**
     * 获取isCallbackable
     *
     * @param fiOrderResp
     * @return
     */
    private Boolean getIsCallbackable(FiOrderResp fiOrderResp) {
        return fiOrderResp.getStatus() == STATUS_COMPLETED
                || fiOrderResp.getStatus() == STATUS_FAILED
                && StringUtils.hasText(fiOrderResp.getNotifyUrl());
    }

    /**
     * 获取isRunmon数据
     *
     * @param fiOrderResp
     * @return
     */
    private Boolean getIsRunmon(FiOrderResp fiOrderResp) {
        if (fiOrderResp.getTxnMode() == TXN_MODE_BANK) {
            return fiOrderResp.getStatus() == STATUS_PENDING || fiOrderResp.getStatus() == STATUS_PROCESSING
                    && diffInSeconds(fiOrderResp.getUpdatedAt()) >= 900;
        } else if (fiOrderResp.getIsTpi()) {
            if (fiOrderResp.getTxnMode() == TXN_MODE_VNPAY_BANK) {
                return fiOrderResp.getStatus() == STATUS_MANUAL_PROCESS
                        && (diffInSeconds(fiOrderResp.getUpdatedAt()) >= 900);
            } else {
                return fiOrderResp.getStatus() == STATUS_PENDING
                        || fiOrderResp.getStatus() == STATUS_PROCESSING
                        || fiOrderResp.getStatus() == STATUS_MANUAL_PROCESS
                        && (diffInSeconds(fiOrderResp.getCreatedAt()) >= 60
                        && diffInSeconds(fiOrderResp.getCreatedAt(), fiOrderResp.getUpdatedAt()) < 10
                        || diffInSeconds(fiOrderResp.getUpdatedAt()) >= 900);
            }
        }
        return false;
    }

    /**
     * 计算当前时间与传入时间的差，结果为秒
     *
     * @param date
     * @return
     */
    private long diffInSeconds(Date date) {
        return (System.currentTimeMillis() - date.getTime()) / 1000;
    }

    /**
     * 计算传入时间的差，结果为秒
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return
     */
    private long diffInSeconds(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / 1000;
    }

    /**
     * 处理message
     *
     * @param fiOrderResp
     * @return
     */
    private String getFiMessage(FiOrderResp fiOrderResp) {
        if (fiOrderResp.getMessage().equals("FI_PENDING_OVER_TIME")) {
            if (fiOrderResp.getIsTunaIn() == 0) {
                return "FI_PENDING_OVER_TIME, Redirect failed";
            } else if (fiOrderResp.getIsLogIn() == 1) {
                return "FI_PENDING_OVER_TIMES";
            }
        }

        if (fiOrderResp.getMessage().equals("CUSTOMER_CANCELLED_TRANSACTION")) {
            if (fiOrderResp.getIsTunaIn() == 0) {
                return "CUSTOMER_CANCELLED_TRANSACTION, Redirect failed";
            } else if (fiOrderResp.getIsLogIn() == 1) {
                return "CUSTOMER_CANCELLED_TRANSACTIONS";
            }
        }

        if (fiOrderResp.getMessage().equals("OTP_TIME_OUT") && fiOrderResp.getIsOtpIn() == 1) {
            return "OTP_TIME_OUTS";
        }

        return fiOrderResp.getMessage();
    }

    /**
     * QRPay充值订单处理
     *
     * @author yangxy
     * @version 创建时间：2023年9月7日 下午3:22:02
     */
    @SuppressWarnings("unchecked")
    public void createOrderByQRPay(SysMerchantInfo sysMerchantInfoEntity, FiCreateOrderReq fiCreateOrderReq) {
        if (!redisUtils.hasKey(fiCreateOrderReq.getOrder_type())) {
            throw new BusinessException("订单类型不存在");
        }

        int txnMode = (int) redisUtils.get(fiCreateOrderReq.getOrder_type());
        checkRequestAmount(sysMerchantInfoEntity, fiCreateOrderReq.getRequest_amount(), txnMode);

        SysBankCardGroupEntity sysBankCardGroupEntity = sysBankCardGroupService
                .getById(sysMerchantInfoEntity.getBankGroupId());
        if (ObjectUtils.isEmpty(sysBankCardGroupEntity)) {
            throw new BusinessException("商户卡群不存在");
        }
        Random rand = new Random();
        // VND QR 银行参数为null，则随机给予银行代号
        if (StringUtils.isEmpty(fiCreateOrderReq.getFrom_bank()) && sysBankCardGroupEntity.getCurrency().equals("kVND")
                && txnMode == TxnModeEnums.TXN_MODE_QRPAY.value) {
            List<SysAvailableBankEntity> sysAvailableBankList = (List<SysAvailableBankEntity>) redisUtils
                    .get(RedisKeyEnums.AVAILABLE_BANK.key);
            List<String> sysAvailableBankCodeList = sysAvailableBankList.stream()
                    .map(SysAvailableBankEntity::getBankCode).collect(Collectors.toList());
            String bankCode = sysAvailableBankCodeList.get(rand.nextInt(sysAvailableBankCodeList.size()));
            fiCreateOrderReq.setFrom_bank(bankCode);
        }

        // 获取可跨行银行code
        List<SysConfigDetail> sysConfigDetailList = (List<SysConfigDetail>) redisUtils
                .get(RedisKeyEnums.CONFIG_KEY + "jump_bank");
        List<String> jumpBankCodeList = sysConfigDetailList.stream().map(SysConfigDetail::getValue)
                .collect(Collectors.toList());
        if (sysBankCardGroupEntity.getCurrency().equals("kVND") && txnMode == TxnModeEnums.TXN_MODE_QRPAY.value
                && jumpBankCodeList.contains(fiCreateOrderReq.getFrom_bank())) {
            List<String> sysAvailableBankCodeList = sysAvailableBankMapper.getSysAvailableBankCodeList(sysMerchantInfoEntity.getBankGroupId(), jumpBankCodeList, Lists.newArrayList(2, 5));
            if (!sysAvailableBankCodeList.isEmpty()) {
                String bankCode = sysAvailableBankCodeList.get(rand.nextInt(sysAvailableBankCodeList.size()));
                fiCreateOrderReq.setFrom_bank(bankCode);
            }
        }

        //根据银行code获取系统可用银行对象
        SysAvailableBankEntity sysAvailableBankEntity = null;
        if (!StringUtils.isEmpty(fiCreateOrderReq.getFrom_bank())) {
            List<SysAvailableBankEntity> list = sysAvailableBankService.list(new LambdaQueryWrapper<SysAvailableBankEntity>().eq(SysAvailableBankEntity::getBankCode, fiCreateOrderReq.getFrom_bank()));
            sysAvailableBankEntity = list.get(0);
        }
    }

    /**
     * 校验商户请求金额是否满足商户要求
     *
     * @param sysMerchantInfoEntity 商户信息对象
     * @param requestAmount         请求金额
     * @param type                  交易类型
     * @author yangxy
     * @version 创建时间：2023年9月7日 下午3:48:41
     */
    private void checkRequestAmount(SysMerchantInfo sysMerchantInfoEntity, BigDecimal requestAmount, int type) {
        switch (type) {
            case 1:// 银行充值
                if (requestAmount.compareTo(sysMerchantInfoEntity.getFiBankMax()) > 0) {
                    throw new BusinessException("请求金额超过商户最大银行充值金额");
                }
                if (requestAmount.compareTo(sysMerchantInfoEntity.getFiBankMin()) < 0) {
                    throw new BusinessException("请求金额不满足商户最小银行充值金额");
                }
                break;
            case 2:// qr充值
                if (requestAmount.compareTo(sysMerchantInfoEntity.getFiQrMax()) > 0) {
                    throw new BusinessException("请求金额超过商户最大qrpay充值金额");
                }
                if (requestAmount.compareTo(sysMerchantInfoEntity.getFiQrMin()) < 0) {
                    throw new BusinessException("请求金额不满足商户最小qrpay充值金额");
                }
                break;
            case 3:// TrueWallet 充值
                if (requestAmount.compareTo(sysMerchantInfoEntity.getFiTwMax()) > 0) {
                    throw new BusinessException("请求金额超过商户最大TrueWallet充值金额");
                }
                if (requestAmount.compareTo(sysMerchantInfoEntity.getFiTwMin()) < 0) {
                    throw new BusinessException("请求金额不满足商户最小TrueWallet充值金额");
                }
                break;
        }
    }

    /**
     * 正式创建充值订单
     *
     * @param sysMerchantInfoEntity 商户信息对象
     * @param fiCreateOrderReq      请求参数对象
     * @param availableBankId       系统可用银行ID
     * @param txnMode               充值类型
     * @author yangxy
     * @version 创建时间：2023年9月8日 上午10:48:35
     */
    @SuppressWarnings({"unchecked", "unused"})
    private boolean startCreateOrder(SysMerchantInfo sysMerchantInfoEntity, FiCreateOrderReq fiCreateOrderReq, Long availableBankId, int txnMode) {
        SysFiOrderEntity sysFiOderEntity = new SysFiOrderEntity();

        // 如果用户选择了 QR 支付，就判断用户选择的银行是否支持 QR，不支持就抛出一个错误
        if (txnMode == TxnModeEnums.TXN_MODE_QRPAY.value || txnMode == TxnModeEnums.TXN_MODE_TRUE_WALLET.value) {
            List<String> qrBankCodeList = (List<String>) redisUtils.get(RedisKeyEnums.QR_BANKCODE.key);
            if (!StringUtils.isEmpty(fiCreateOrderReq.getFrom_bank()) && !qrBankCodeList.contains(fiCreateOrderReq.getFrom_bank())) {
                sysFiOderEntity.setRate(new BigDecimal(0));
                sysFiOderEntity.setFromAccName("");
                sysFiOderEntity.setFromBank(fiCreateOrderReq.getFrom_bank());
                sysFiOderEntity.setFromBankCardNumber("");
                sysFiOderEntity.setCurrency(sysMerchantInfoEntity.getCurrency());
                sysFiOderEntity.setStatus(5);
                sysFiOderEntity.setStatusDescription(0);
                sysFiOderEntity.setMessage("NO_QR_SERVICE");
//				throws new RuntimeErrorException("NO QR SERVICE. This bank doesn't provide the QR PAY payment.");
                return false;
            }

            if (isRandomAount(txnMode, sysMerchantInfoEntity.getCurrency())) {
                fiCreateOrderReq.setNewAmount(getRandomAmount(sysMerchantInfoEntity, fiCreateOrderReq.getFrom_bank(), fiCreateOrderReq.getRequest_amount()));
            }

            //获取银行卡信息
            List<SysBankCardEntity> bankCardList = null;
            if (!ObjectUtils.isEmpty(fiCreateOrderReq.getNewAmount())) {//存在随机金额
                bankCardList = sysBankCardMapper.getBankCardList(txnMode, sysMerchantInfoEntity.getCurrency(), fiCreateOrderReq.getNewAmount(), fiCreateOrderReq.getFrom_bank());
            } else {
                bankCardList = sysBankCardMapper.getBankCardList(txnMode, sysMerchantInfoEntity.getCurrency(), fiCreateOrderReq.getRequest_amount(), fiCreateOrderReq.getFrom_bank());
            }

            if (!bankCardList.isEmpty()) {
                boolean txnModeChange = false;
                switch (sysMerchantInfoEntity.getCurrency()) {
                    case "THB"://泰国
                        if (txnMode == TxnModeEnums.TXN_MODE_QRPAY.value || txnMode == TxnModeEnums.TXN_MODE_TRUE_WALLET.value) {
                            txnMode = TxnModeEnums.MODE_QR_AND_TRUE_WALLET.value;
                            txnModeChange = true;
                        }
                        break;
                    case "kVND":// 越南
                    case "kIDR":// 印尼
                        if (txnMode == TxnModeEnums.TXN_MODE_QRPAY.value || txnMode == TxnModeEnums.TXN_MODE_BANK.value) {
                            txnMode = TxnModeEnums.MODE_IB_AND_QR.value;
                            txnModeChange = true;
                        }
                        break;
                }
                //交易模式变化后重新获取银行卡信息
                if (txnModeChange) {
                    bankCardList = sysBankCardMapper.getBankCardList(txnMode, sysMerchantInfoEntity.getCurrency(), fiCreateOrderReq.getRequest_amount(), fiCreateOrderReq.getFrom_bank());
                }
            }

            if (bankCardList.isEmpty()) {
                //todo 充值订单（fi100）添加失败交易记录
                return false;
            }
            SysBankCardEntity sysBankCardEntity = bankCardList.get(0);
            sysFiOderEntity.setBankCardId(sysBankCardEntity.getId());

            //todo 组装充值订单（fi100）信息并存入数据库

        }
        return false;
    }

    /**
     * 是否需要随机金额
     *
     * @param txnMode  交易模式
     * @param currency 币种
     * @return
     * @author yangxy
     * @version 创建时间：2023年9月12日 上午10:24:04
     */
    @SuppressWarnings("unchecked")
    public boolean isRandomAount(int txnMode, String currency) {
        if (txnMode != TxnModeEnums.TXN_MODE_QRPAY.value || txnMode != TxnModeEnums.TXN_MODE_TRUE_WALLET.value) {
            return false;
        }
        if ("CNY".equals(currency)) {
            return false;
        }

        //目前不支持小数点后不是二位数的货币
        List<SysCurrencyConfigEntity> sysCurrencyConfigEntityList = (List<SysCurrencyConfigEntity>) redisUtils.get(RedisKeyEnums.SYS_CURRENCY.key);
        for (SysCurrencyConfigEntity bean : sysCurrencyConfigEntityList) {
            if (bean.getCurrencyAbb().equals(currency) && bean.getDecimalPlaces() != 2) {
                throw new BusinessException("Unsupported currency.");
            }
        }

        return true;
    }

    /**
     * 生成随机金额
     *
     * @param sysMerchantInfoEntity 商户对象
     * @param bankCode              银行code
     * @param orderAmount           订单金额
     * @return
     * @author yangxy
     * @version 创建时间：2023年9月12日 上午11:01:40
     */
    @SuppressWarnings("unchecked")
    public BigDecimal getRandomAmount(SysMerchantInfo sysMerchantInfoEntity, String bankCode, BigDecimal orderAmount) {
        switch (sysMerchantInfoEntity.getCurrency()) {
            case "kIDR"://印尼
                //银行属于需要用户手动输入附言 ID 的银行并且商户启用使用 QR 附言不使用随机金额
                ConfigRedisRsp configRedisRsp = (ConfigRedisRsp) redisUtils.get(RedisKeyEnums.CONFIG_KEY.key + "pairing_bank");
                Map<String, ConfigRedisRspSub> configRedisRspSubMap = configRedisRsp.getConfigRedisRspSubMap();
                if (sysMerchantInfoEntity.getUseQrPairingCode() == 1 && configRedisRspSubMap.containsKey(bankCode)) {
                    return orderAmount;
                }
            case "kVND"://越南
                if (sysMerchantInfoEntity.getNoQrAdj() == 2) {
                    return orderAmount;
                }
                BigDecimal roanDom = null;
                String orderAmountStr = orderAmount.toString();
                //订单金额有小数并且尾数为0
                if (orderAmountStr.indexOf(".") >= 0 && orderAmountStr.endsWith("0")) {
                    switch (bankCode) {
                        case "BCA":
                            roanDom = new BigDecimal(String.valueOf((int) (Math.random() * 200 + 1) / 1000.0));
                            break;
                        case "TYP":
                            roanDom = new BigDecimal(String.valueOf((int) (Math.random() * 99 + 1) / 100.0));
                            break;
                        default:
                            roanDom = new BigDecimal(String.valueOf((int) (Math.random() * 99 + 1) / 1000.0));
                    }
                    return orderAmount.subtract(roanDom);
                } else {
                    roanDom = new BigDecimal(String.valueOf((int) (Math.random() * 98 + 1) / 1000.0));
                    BigDecimal subtract = orderAmount.subtract(roanDom);
                    //金额有小数并且尾数为0时再减去0.001
                    if (subtract.toString().indexOf(".") > 0 && subtract.toString().endsWith("0")) {
                        return subtract.subtract(new BigDecimal("0.001"));
                    }
                    return subtract;
                }
        }
        BigDecimal roanDom = new BigDecimal(String.valueOf((int) (Math.random() * 99 + 1) / 100.0));
        return orderAmount.subtract(roanDom);

    }

    /**
     * 生成token
     *
     * @param sysFiOderEntity fi充值订单对象
     * @param replaceUrl
     * @return
     * @author yangxy
     * @version 创建时间：2023年9月12日 下午5:06:07
     */
    public String createToken(SysFiOrderEntity sysFiOderEntity, String replaceUrl) {
        //todo 组装token生成参数并生成token

        //通知迅银捞帐参数
        Map<String, Object> paramMap = Maps.newHashMap();
        amqUtils.sendDelayedMsg(AmqEnum.APP_SALVAGE_ACCOUNT.exchange, AmqEnum.APP_SALVAGE_ACCOUNT.routingKey, paramMap, 10);
        return "";
    }

    public static void main(String[] args) {
//		System.out.println(1);
//		for(int i=0;i<100;i++) {
//		int random = (int)(Math.random()*100+1);
//		double d = random / 1000.0;
//		System.out.println(String.valueOf((int)(Math.random()*100+1) / 1000.0)+"-");
//		}
        BigDecimal bigDecimal = new BigDecimal("1.10");
        BigDecimal bigDecimal1 = new BigDecimal("0.301");
        System.out.print(bigDecimal.subtract(bigDecimal1));
    }
}
